#ifndef _QQ_QQ_H_
#define _QQ_QQ_H_

#include <gtk/gtk.h>
#include "internal.h"
#include "accountopt.h"
#include "conversation.h"
#include "multi.h"
#include "notify.h"
#include "request.h"

#include "proxy.h"
#include "account.h"
#include "debug.h"
#include "prpl.h"
#include "common.h"

#define QQ_CONNECT_STEPS 2				// steps in QQ login

#define QQ_KEY_LENGTH 16
#define QQ_LOGIN_DATA_LENGTH 69 

#define QQ_GROUP_NAME "QQ Buddies"
#define QQ_GROUP_UNKNOWN "QQ Unknown Buddies"

#define QQ_HOST "61.141.194.223"	// default QQ server
#define QQ_PORT 8000							// default QQ port

#define QQ_DEFAULT_LOCALE "GBK"

#define QQ_SENDQUEUE_TIMEOUT 2500 // in 1/1000 sec
#define QQ_MAX_RESEND 5 // max resend times

#define QQ_NAME_LENGTH_MAX 250 // max length of nickname
#define QQ_MSG_IM_MAX 600
#define QQ_CONTACT_FIELDS 36

#define QQ_STATUS_MESSAGE_LENGTH_MAX QQ_MSG_IM_MAX

// the first two bytes in packet_header structure
// it indicates the source/ver of the sender
#define QQ_CLIENT_062E 0x062e // client GB QQ2000c build 630
#define QQ_CLIENT_072E 0x072e // client En QQ2000c build 305
#define QQ_CLIENT_0801 0x0801 // client En QQ2000c build 630
#define QQ_CLIENT_0A1D 0x0a1d // client Gb QQ2003c build 0808
#define QQ_CLIENT_0B07 0x0b07 // client Gb QQ2003c build 0925
#define QQ_SERVER_0100 0x0100 // server

#define QQ_CLIENT      QQ_CLIENT_0B07

#define QQ_PACKET_TAG  0x02 // all QQ text chat packets starts with it
#define QQ_PACKET_TAIL 0x03	// all QQ packets use this at the end

#define QQ_LOGIN_MODE_NORMAL 0x0a
#define QQ_LOGIN_MODE_HIDDEN 0x28

#define QQ_BUDDY_GENDER_GG 0
#define QQ_BUDDY_GENDER_MM 1
#define QQ_BUDDY_GENDER_UNKNOWN 0xff

#define QQ_BUDDY_FLAG_QQ_MEMBER 0x01
#define QQ_BUDDY_FLAG_MOBILE 0x010
#define QQ_BUDDY_FLAG_BIND_MOBILE 0x20

#define QQ_BUDDY_ONLINE_NORMAL 10
#define QQ_BUDDY_ONLINE_OFFLINE 20
#define QQ_BUDDY_ONLINE_AWAY 30
#define QQ_BUDDY_ONLINE_INVISIBLE 40

#define QQ_ICON_SUFFIX_NORMAL 1
#define QQ_ICON_SUFFIX_OFFLINE 2
#define QQ_ICON_SUFFIX_AWAY 3
#define QQ_ICON_SUFFIX_DEFAULT 2

#define QQ_LOGIN_REPLY_OK 0x00
#define QQ_LOGIN_REPLY_REDIRECT 0x01
#define QQ_LOGIN_REPLY_PWD_ERROR 0x02

#define QQ_BUDDY_INFO_ENDING 0x2d
#define QQ_CHANGE_ONLINE_STATUS_REPLY_OK 0x30
#define QQ_SEND_IM_REPLY_OK 0x00

#define QQ_FRIENDS_ONLINE_POSITION_START 0x00
#define QQ_FRIENDS_ONLINE_POSITION_END 0xff
#define QQ_FRIENDS_LIST_POSITION_START 0x0000
#define QQ_FRIENDS_LIST_POSITION_END 0xffff

#define QQ_SEND_IM_BEFORE_MSG_LEN 53
#define QQ_SEND_IM_AFTER_MSG_LEN 13 // there is one 0x00 at the end of msg

// list of QQ commands
enum {
	QQ_CMD_LOGOUT	= 0x0001,	// log out
	QQ_CMD_KEEP_ALIVE = 0x0002, // advertisement message from tencent
	QQ_CMD_UPDATE_INFO = 0x0004, // update information
	QQ_CMD_SEARCH_USER = 0x0005, // serach for user
	QQ_CMD_GET_USER_INFO = 0x0006, // get user information
	QQ_CMD_ADD_FRIEND_WO_AUTH = 0x0009, // add friend without authentication
	QQ_CMD_DEL_FRIEND = 0x000a, // delete a friend 
	QQ_CMD_ADD_FRIEND_W_AUTH = 0x000b, // add friend with authentication
	QQ_CMD_CHANGE_ONLINE_STATUS = 0x000d, // change my online status
	QQ_CMD_ACK_SYS_MSG = 0x0012, // ack system message
	QQ_CMD_SEND_IM = 0x0016, // send message
	QQ_CMD_RECV_IM = 0x0017, // receive message
	QQ_CMD_REMOVE_SELF = 0x001c, // remove self from other's list
	QQ_CMD_LOGIN = 0x0022, // login
	QQ_CMD_GET_FRIENDS_LIST = 0x0026, // retrieve my freinds list
	QQ_CMD_GET_FRIENDS_ONLINE = 0x0027, // get my online friends list
	QQ_CMD_MACRO_CMD = 0x0030, // macro command ??? I do not know
	QQ_CMD_RECV_MSG_SYS = 0x0080, // receive a system message
	QQ_CMD_RECV_MSG_FRIEND_CHANGE_STATUS = 0x0081, // friends change status
};

enum {
	QQ_IM_TEXT = 0x01,
	QQ_IM_AUTO_REPLY = 0x02,
};

enum {
	QQ_RECV_IM_TO_BUDDY = 0x0009,
	QQ_RECV_IM_TO_UNKNOWN = 0x000a,
	QQ_RECV_IM_GROUP_INFO = 0x0020,
	QQ_RECV_IM_ADD_TO_GROUP = 0x0021,
	QQ_RECV_IM_DEL_FROM_GROUP = 0x0022,
	QQ_RECV_IM_APPLY_ADD_TO_GROUP = 0x0023,
	QQ_RECV_IM_APPROVE_APPLY_ADD_TO_GROUP = 0x0024,
	QQ_RECV_IM_REJCT_APPLY_ADD_TO_GROUP = 0x0025,
	QQ_RECV_IM_CREATE_GROUP = 0x0026,
	QQ_RECV_IM_SYS_NOTIFICATION = 0x0030,
};

enum {
	QQ_SELF_STATUS_AVAILABLE = 0x11, // I determined value, no meaning
	QQ_SELF_STATUS_AWAY,
	QQ_SELF_STATUS_INVISIBLE,
	QQ_SELF_STATUS_CUSTOM,
	QQ_SELF_STATUS_IDLE,
};

enum {
	QQ_AUTH_NO_AUTH = 0,
	QQ_AUTH_NEED_AUTH = 1,
	QQ_AUTH_NO_ADD = 2,
};

enum {
	QQ_CONTACT_OPEN = 0,
	QQ_CONTACT_ONLY_FRIENDS = 1,
	QQ_CONTACT_CLOSE = 2,
};

enum {
	QQ_MSG_SYS_BEING_ADDED = 1,
	QQ_MSG_SYS_ADD_CONTACT_REQUEST = 2,
	QQ_MSG_SYS_ADD_CONTACT_APPROVED = 3,
	QQ_MSG_SYS_ADD_CONTACT_REJECTED = 4,
};

struct qq_sendpacket {
  int fd;
  int type;
  int send_seq;
  int resend_times;
  time_t sendtime;
  char *buf;
  int len;
};

struct gc_and_packet {
	GaimConnection *gc;
	struct qq_sendpacket *packet;
};

struct qq_info_query {
	int uid;
	gboolean show_window;
	struct contact_info *ret_info;
};

struct qq_add_buddy_request {
	uint16 seq;
	int uid;
};

struct qq_friends_online_entry {
	int uid;
	char ip[16];
	uint16 port;
	uint8  status;
	uint16 unknown1;
	uint8  unknown_key[QQ_KEY_LENGTH];
	uint8  flag;
};

struct qq_buddy_change_status {
	int uid;
	char ip[16];
	uint16 port;
	uint8 status;
	uint16 unknown1;
	uint8 unknown_key[QQ_KEY_LENGTH];
	uint32 my_uid;
};

struct qq_buddy {
	int uid;
	uint8 icon;
	uint8 icon_suffix;
	uint8 age;
	uint8 gender;
	uint8 nickname_len;
	uint8 nickname[QQ_NAME_LENGTH_MAX];
	gboolean online;
	char ip[16];
	uint16 port;
	uint8 status;
	uint8 flag;
	time_t signon;
	time_t idle;
};

struct qq_login_reply_ok_packet {
	uint8  result;
	uint8  session_key[QQ_KEY_LENGTH];
	int    uid;
	uint32 client_ip; // those detected by server
	uint16 client_port;
	uint32 server_ip;
	uint16 server_port;
	time_t login_time;
	uint8  unknown1[26]; // 037-062
	uint32 unknown_server1_ip;
	uint16 unknown_server1_port;
	uint32 unknown_server2_ip;
	uint16 unknown_server2_port;
	uint16 seperator[1]; // 0x0000
	uint8  unknown2[32]; // 077-108
	uint8  unknown3[12]; // 109-120, all 0x00
	uint32 last_client_ip;
	time_t last_login_time;
	time_t last_logout_time;
	uint8  unknown[8]; //129-136, all 0x00
};

struct qq_login_reply_redirect_packet {
	uint8 result;
	uint32 uid;
	uint8 new_server_ip[4];
	uint16 new_server_port;
};

struct qq_rev_msg_header {
	uint8  header_tag;
	uint16 source_tag;
	uint16 cmd;
	uint16 seq; // can be ack_seq or send_seq, depends on cmd
};

struct contact_info {
  gchar* uid; 						//0
  gchar* nick; 						//1
  gchar* country; 				//2 
  gchar* province; 				//3
  gchar* zipcode; 				//4
  gchar* address;					//5
  gchar* tel;							//6
  gchar* age;							//7
  gchar* gender;					//8
  gchar* name;						//9
  gchar* email;						//10
	gchar* pager_sn;				//11
	gchar* pager_num;				//12
	gchar* pager_sp;				//13
	gchar* pager_base_num;	//14
	gchar* pager_type;			//15
  gchar* occupation;			//16
  gchar* homepage;				//17
	gchar* auth_type;				//18
	gchar* unknown1;				//19
	gchar* unknown2;				//20
	gchar* face;						//21
	gchar* hp_num;					//22
	gchar* hp_type;					//23
  gchar* intro;						//24
  gchar* city;						//25
	gchar* unknown3;				//26
	gchar* unknown4;				//27
	gchar* unknown5;				//28
	gchar* is_open_hp;			//29
	gchar* is_open_contact;	//30
  gchar* college;					//31
	gchar* horoscope;				//32
	gchar* zodiac; 					//33 sheng xiao
  gchar* blood;						//34
	gchar* qq_show;					//35
};

struct _updating_contact_info {
  uint32 uid;
  GtkWidget *window;
  GtkWidget *refresh_button;
  GtkWidget *face,
						*uid_entry,
						*nick,
						*country,
						*age,
						*gender,
						*province,
						*city,
						*email,
						*address,
						*zipcode,
						*tel,
						*name,
						*blood,
						*college,
       		 	*occupation,
						*zodiac,
						*horoscope,
						*homepage,
						*intro;
	GtkWidget *open_contact_radio[3];
  GtkWidget *auth_radio[3],
						*is_modify_passwd, 
						*old_password, 
						*password[2];
	struct contact_info *old_info;
};

struct qq_data {
	int fd;				// socket file handler
	int uid;			// QQ number
	uint8 inikey[16]; // initial key to encrypt login packet
	uint8 pwkey[16]; // password in md5 (or md5' md5)
	uint8 session_key[16]; // later use this as key in this session
	
	uint16 send_seq; // send sequence number
	uint8 login_mode;// online of invisible
	uint8 status; // 
	gboolean logged_in; // used by qq-add_buddy

	uint8 my_ip[16];
	uint16 my_port;
	uint8  my_icon;
	uint32 all_online;
	
	uint8 window[1<<13];
	gint sendqueue_timeout;
	GList *updateinfo;
	GList *sendqueue;
	GList *info_query;
	GList *add_buddy_request;
};

void qq_send_packet_get_info
(GaimConnection *gc, int uid, gboolean show_window);

void qq_send_packet_modify_info
(GaimConnection *gc, struct contact_info *info, gchar *new_passwd);

#endif
